package com.bruce.learnrecylerview.app.data;

import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;
import com.bruce.commonutils.RetrofitUtils;
import com.bruce.commonutils.SimpleXmlConverter;
import com.bruce.commonutils.UrlUtils;
import com.bruce.learnrecylerview.app.model.local.Latest;
import com.bruce.learnrecylerview.app.model.local.My;
import com.bruce.learnrecylerview.app.model.shjt.ShanghaiUrls;
import com.bruce.learnrecylerview.app.model.shjt.alllines.LineXml;
import com.bruce.learnrecylerview.app.model.shjt.alllines.PdLineXml;
import com.bruce.learnrecylerview.app.model.shjt.alllines.PxLineXml;
import com.bruce.learnrecylerview.app.model.shjt.carmonitor.Result;
import com.bruce.learnrecylerview.app.model.shjt.getline.LineInfoDetail;
import com.bruce.learnrecylerview.app.model.shjt.lineinfo.LineInfo;
import com.bruce.learnrecylerview.app.model.shjt.lineinfo.PdLineInfo;
import com.bruce.learnrecylerview.app.model.shjt.lineinfo.PxLineInfo;
import com.github.bluzwang.aopcache.cache.Cache;
import retrofit.RestAdapter;
import retrofit.http.GET;
import retrofit.http.Path;
import retrofit.http.Query;
import rx.Observable;

import javax.inject.Inject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


/**
 * Created by Bruce-Home on 2015/8/22.
 */
public class WebApi {
    private final WifiManager mWifi;

    @Inject
    public WebApi(WifiManager mWifi) {
        this.mWifi = mWifi;
    }

    private static ShanghaiUrls urls = null;
    private static final String LOCOL_END_POINT = "http://192.168.1.66:8080/";
    private static final String END_POINT = "http://mt58866.xicp.net:66/";
    private static final String SHJT_END_POINT = "http://jt.sh.cn/";
    private static final String[] localWifis = new String[]{"e8:cd:2d:2c:3b:c8", "e8:cd:2d:2c:3b:cc", "08:bd:43:d5:9f:e0"};

    private interface MyWebService {
        @GET("/latest.php")
        Observable<Latest> requestLatest();

        @GET("/getmy.php")
        Observable<My> requestMy(@Query("time") String time, @Query("ispx") int ispx);

        @GET("/getmy.php")
        My requestMySync(@Query("time") String time, @Query("ispx") int ispx);
    }

    private interface SHJTWebService {
        @GET("/trafficWeb/lbs/modify.xml")
        Observable<ShanghaiUrls> requestUrls();

        @GET("/trafficWeb/lbs/modify.xml")
        ShanghaiUrls requestUrlsSync();

        @GET("/trafficWeb/lbs/px.xml")
        Observable<PxLineXml> requestPxLines();

        @GET("/trafficWeb/lbs/pd.xml")
        Observable<PdLineXml> requestPdLines();
    }

    private interface PxWebService {
        @GET("/{path}")
        Observable<PxLineInfo> requestLineInfo(@Path(value = "path", encode = false) String path,
                                               @Query("name") String name,
                                               @Query("my") String my,
                                               @Query("t") String time);

        @GET("/{path}")
        Observable<LineInfoDetail> requestLineInfoDetail(@Path(value = "path", encode = false) String path,
                                                         @Query("lineid") String lineid,
                                                         @Query("my") String my,
                                                         @Query("t") String time);

        @GET("/{path}")
        Observable<Result> requestResult(@Path(value = "path", encode = false) String path,
                                         @Query("lineid") String lineid,
                                         @Query("my") String my,
                                         @Query("t") String time,
                                         @Query("direction") boolean direction,
                                         @Query("stopid") String stopid);
    }

    private interface PdWebService {
        @GET("/{path}")
        Observable<PdLineInfo> requestLineInfo(@Path(value = "path", encode = false) String Path,
                                               @Query("linename") String name,
                                               @Query("my") String my,
                                               @Query("t") String time);

        @GET("/{path}")
        Observable<LineInfoDetail> requestLineInfoDetail(@Path(value = "path", encode = false) String path,
                                                         @Query("lineid") String lineid,
                                                         @Query("my") String my,
                                                         @Query("t") String time);

        @GET("/{path}")
        Observable<Result> requestResult(@Path(value = "path", encode = false) String path,
                                         @Query("lineid") String lineid,
                                         @Query("my") String my,
                                         @Query("t") String time,
                                         @Query("direction") int direction,
                                         @Query("stopid") String stopid);
    }

    private MyWebService getLocalWebService() {
        WifiInfo wifiInfo = mWifi.getConnectionInfo();
        String thisWifi = wifiInfo.getBSSID();
        Log.d("bruce", "bssid = " + thisWifi);
        for (String wifi : localWifis) {
            if (wifi.equals(thisWifi)) {
                // in local
                return localWebService;
            }
        }
        return globalWebService;
    }

    private final RestAdapter localRestAdapter = new RestAdapter.Builder()
            .setEndpoint(LOCOL_END_POINT)
            .setClient(RetrofitUtils.newClient(3))
            .build();

    private final RestAdapter globalRestAdapter = new RestAdapter.Builder()
            .setEndpoint(END_POINT)
            .setClient(RetrofitUtils.newClient(3))
          //  .setLogLevel(RestAdapter.LogLevel.FULL)
            .build();

    private final RestAdapter shjtRestAdapter = new RestAdapter.Builder()
            .setEndpoint(SHJT_END_POINT)
            .setClient(RetrofitUtils.newClient(3))
            .setConverter(new SimpleXmlConverter())
            .build();

    private final MyWebService localWebService = localRestAdapter.create(MyWebService.class);
    private final MyWebService globalWebService = globalRestAdapter.create(MyWebService.class);
    private final SHJTWebService shjtWebService = shjtRestAdapter.create(SHJTWebService.class);
    private PxWebService pxWebService;
    private PdWebService pdWebService;

    private final byte[] blockPx = new byte[0], blockPd = new byte[0], blockUrl = new byte[0];

    private  void initPxWebServiceIfNeed() {
        if (pxWebService != null) {
            return;
        }
        synchronized (blockPx) {
            if (pxWebService != null) {
                return;
            }
            pxWebService = new RestAdapter.Builder()
                    .setEndpoint(UrlUtils.getEndPoint(urls.getPx_get_line_info_by_name()))
                    .setConverter(new SimpleXmlConverter())
                    .setClient(RetrofitUtils.newClient(3))
                            .setLogLevel(RestAdapter.LogLevel.FULL)
                    .build()
                    .create(PxWebService.class);
        }
    }

    private void initPdWebServiceIfNeed() {
        if (pdWebService != null) {
            return;
        }
        synchronized (blockPd) {
            if (pdWebService != null) {
                return;
            }
            pdWebService = new RestAdapter.Builder()
                    .setEndpoint(UrlUtils.getEndPoint(urls.getPd_get_line_info_by_name()))
                    .setConverter(new SimpleXmlConverter())
                    .setClient(RetrofitUtils.newClient(3))
                            .setLogLevel(RestAdapter.LogLevel.FULL)
                    .build()
                    .create(PdWebService.class);
        }
    }

    @Cache
    private Observable<ShanghaiUrls> requestUrlsInternal() {
        return shjtWebService.requestUrls();
    }


    private void initUrlsSyncIfNeed() {
        if (urls != null) {
            return;
        }
        synchronized (blockUrl) {
            if (urls != null) {
                return;
            }
            requestUrlsInternal().subscribe(shanghaiUrls -> {
                urls = shanghaiUrls;
            });
        }
    }

    private Observable<My> initAndRequestMy(boolean isPx) {
        String now = new SimpleDateFormat("yyyy-MM-ddHH:mm", Locale.US).format(new Date());
        return Observable.just(isPx)
                .flatMap(p -> {
                    initUrlsSyncIfNeed();
                    initPxWebServiceIfNeed();
                    initPdWebServiceIfNeed();
                    return getMyWeb(now, p);
                });
    }

    @Cache(memTimeOutMs = 60_000, needDbCache = false, logLevel = 1)
    private Observable<My> getMyWeb(String now, boolean isPx) {
        return getLocalWebService().requestMy(now, isPx ? 1 : 0);
    }

    @Cache(logLevel = 1)
    public Observable<LineXml> requestLines(boolean isPx) {
        if (isPx) {
            return shjtWebService.requestPxLines().map(origin -> origin);
        }
        return shjtWebService.requestPdLines().map(origin -> origin);
    }


    @Cache(logLevel = 1)
    public Observable<LineInfo> requestLineInfo(String name, boolean isPx) {
        Observable<My> myOb = initAndRequestMy(isPx);
        if (isPx) {
            return myOb.flatMap(my -> pxWebService.requestLineInfo(UrlUtils.getPath(urls.getPx_get_line_info_by_name()), name, my.getMy(), my.getTime()));
        }
        return myOb.flatMap(my -> pdWebService.requestLineInfo(UrlUtils.getPath(urls.getPd_get_line_info_by_name()), name, my.getMy(), my.getTime()));
    }


    @Cache(logLevel = 1)
    public Observable<LineInfoDetail> requestLineInfoDetail(String lineid, boolean isPx) {
        Observable<My> myOb = initAndRequestMy(isPx);
        Observable<LineInfoDetail> ob;
        if (isPx) {
            ob = myOb.flatMap(my -> pxWebService.requestLineInfoDetail(UrlUtils.getPath(urls.getPx_get_line()), lineid, my.getMy(), my.getTime()));
        } else {
            ob = myOb.flatMap(my -> pdWebService.requestLineInfoDetail(UrlUtils.getPath(urls.getPd_get_line()), lineid, my.getMy(), my.getTime()));
        }
        return ob.map(lineInfoDetail -> {
            lineInfoDetail.lineId = lineid;
            return lineInfoDetail;
        });
    }

    public Observable<Result> requestResult(String lineid, boolean direction, String stopid, boolean isPx) {
        Observable<My> myOb = initAndRequestMy(isPx);
        if (isPx) {
            return myOb.flatMap(my -> pxWebService.requestResult(UrlUtils.getPath(urls.getPx_car_monitor()), lineid, my.getMy(), my.getTime(), direction, stopid));
        }
        return myOb.flatMap(my -> pdWebService.requestResult(UrlUtils.getPath(urls.getPd_car_monitor()), lineid, my.getMy(), my.getTime(), direction ? 0 : 1, stopid));
    }
}
